筆記目錄

Skip to content

ASP.NET Core Web API 入門心得 - 改善 Enum 註解

TLDR

  • 預設的 Swashbuckle.AspNetCore 無法自動解析並顯示 Enum 成員的 XML 註解。
  • 使用 JsonStringEnumConverter 可讓 API 支援字串格式的 Enum 輸入與輸出,但無法解決 Swagger 文件可讀性問題。
  • 實作自定義 ISchemaFilter 是解決此問題的最佳方案,可將 XML 文件中的註解注入到 OpenAPI Schema 的 Description 欄位中。
  • 透過 ISchemaFilter 處理 Enum 描述,能同時保留數值傳遞的嚴謹性與文件說明的高可讀性。

問題情境:Swagger 無法顯示 Enum 成員註解

在 ASP.NET Core Web API 專案中,即使在 Enum 定義中撰寫了完整的 XML 註解,Swagger UI 預設仍無法將這些資訊呈現出來。這導致開發者在使用 API 時,無法直接從文件中得知各個 Enum 數值所代表的業務邏輯含義。

什麼情況下會遇到這個問題:當專案使用 Swashbuckle.AspNetCore 產生 OpenAPI 文件,且 API 的 DTO 中包含 enum 型別屬性時。

嘗試方案:使用 JsonStringEnumConverter

部分開發者會嘗試透過 JsonStringEnumConverter 將 Enum 轉換為字串,以提升 API 的可讀性。

  • 設定方式:在 DTO 屬性上標註 [JsonConverter(typeof(JsonStringEnumConverter))] 或在 Program.csAddJsonOptions 中全域設定。
  • 結果分析:雖然 API 的輸入與輸出變成了字串(例如 Sunday 而非 0),但 Swagger UI 的說明欄位依然保持空白或僅顯示數值陣列,並未顯示 XML 中的註解內容。此外,將 Enum 改為字串傳遞可能增加使用端拼寫錯誤的風險。

解決方案:實作自定義 ISchemaFilter

為了在不改變 API 傳輸格式的前提下提升文件可讀性,建議實作 ISchemaFilter 來解析 XML 文件,並將註解動態注入至 Swagger 的 Schema 描述中。

實作步驟

  1. 建立 EnumSchemaFilter 類別,負責讀取 XML 文件並將成員描述附加至 schema.Description
  2. Program.csAddSwaggerGen 設定中,註冊該 Filter 並傳入 XML 文件內容。
csharp
public class EnumSchemaFilter : ISchemaFilter {
    private readonly XDocument xmlComments;

    public EnumSchemaFilter(XDocument xmlComments) {
        this.xmlComments = xmlComments;
    }

    public void Apply(OpenApiSchema schema, SchemaFilterContext context) {
        Type enumType = context.Type;

        if (!enumType.IsEnum) {
            return;
        }

        // 避免重複加入描述
        if (schema.Description?.Contains("<p>Possible values:</p>") == true) {
            return;
        }

        StringBuilder sb = new(schema.Description);
        sb.AppendLine("<p>Possible values:</p>");
        sb.AppendLine("<ul>");

        foreach (string enumMemberName in Enum.GetNames(enumType)) {
            string fullEnumMemberName = $"F:{enumType.FullName}.{enumMemberName}";
            string enumMemberDescription = xmlComments.XPathEvaluate(
              $"normalize-space(//member[@name = '{fullEnumMemberName}']/summary/text())"
            ) as string;

            if (string.IsNullOrEmpty(enumMemberDescription)) {
                continue;
            }

            long enumValue = Convert.ToInt64(Enum.Parse(enumType, enumMemberName));
            sb.AppendLine($"<li><b>{enumValue}[{enumMemberName}]</b>: {enumMemberDescription}</li>");
        }

        sb.AppendLine("</ul>");
        schema.Description = sb.ToString();
    }
}

註冊至 Swagger

Program.cs 中進行配置:

csharp
builder.Services.AddSwaggerGen(options => {
    foreach (string xmlFile in Directory.GetFiles(AppContext.BaseDirectory, "*.xml")) {
        XDocument xmlDoc = XDocument.Load(xmlFile);
        options.IncludeXmlComments(() => new XPathDocument(xmlDoc.CreateReader()), true);
        options.SchemaFilter<EnumSchemaFilter>(xmlDoc);
    }
});

執行結果

透過此方式,Swagger UI 的 Schema 描述區塊將會自動列出所有 Enum 成員及其對應的數值、名稱與註解說明,大幅提升 API 文件的參考價值。

swagger enum comments success

異動歷程

  • 2024-04-10 初版文件建立。
  • 2025-01-16 修正 EnumSchemaFilter 會重複加入 enum 專案描述的錯誤。